﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Bookworm.Fx.Indexer
{
    public class EbookIndexer
    {
        private const string Identifier = "EBI";
        private const short Version = 1;
        private const short HeaderLength = 15;
        private const byte ExtendedHeaderFlag = 0;

        private readonly string _sourceDirectory;
        private readonly string _destinationDirectory;
        private HeaderFlags _headerFlags;
        private static bool _isUnsynchronised;
        private static bool _hasExtendedHeader;
        private readonly short _numberOfFrames;
        private readonly int _frameLength;
        private readonly short _frameStartPos;
       
        public bool IsUnsynchronised
        {
            get { return _isUnsynchronised; }
            set
            {
                _isUnsynchronised = value;
                _headerFlags = value ? _headerFlags | HeaderFlags.IsUnsynchronised
                                   : _headerFlags & ~HeaderFlags.IsUnsynchronised;
            }
        }
        public bool HasExtendedHeader
        {
            get { return _hasExtendedHeader; }
            set
            {
                _hasExtendedHeader = value;
                _headerFlags = value ? _headerFlags | HeaderFlags.HasExtendedHeader
                                   : _headerFlags & ~HeaderFlags.HasExtendedHeader;
            }
        }

        public EbookIndexer(string sourceDirectory, string destinationDirectory)
        {
            _sourceDirectory = sourceDirectory;
            _destinationDirectory = destinationDirectory;
            //HACK
            _numberOfFrames = 3;
            _frameLength = 3;
            _frameStartPos = 4;
        }

        public void RebuildIndex()
        {
     
            CreateApplicationFolder();  
          
            string[] fileNames = Directory.GetFiles(_sourceDirectory, "*.pdf",SearchOption.AllDirectories);         
            foreach(string fileName in fileNames)
            {                
                byte[] header = ConstructHeader();
                byte[] extendedHeader = ConstructExtendedHeader(fileName);                
                var binaryWriter = new BinaryWriter(File.Create(Path.ChangeExtension(Path.Combine(_destinationDirectory,Path.GetFileNameWithoutExtension(fileName)),"ebi")));                
                binaryWriter.Write(header);
                binaryWriter.Write(extendedHeader);
                binaryWriter.Close();
                
            }                       
        }

        private byte[] ConstructHeader()
        {
            var encoding = new ASCIIEncoding();
            byte[] hIdentifier = encoding.GetBytes(Identifier);
            byte[] hVersion = BitConverter.GetBytes(Version);
            byte[] hSize = BitConverter.GetBytes(HeaderLength);
            byte hFlag = Reverse((byte)_headerFlags);//should we reverse?
            byte[] hFrameCount = BitConverter.GetBytes(_numberOfFrames);
            byte[] hFrameLength = BitConverter.GetBytes(_frameLength);
            byte[] hFrameStartPos = BitConverter.GetBytes(_frameStartPos);
            var header = new List<byte>(15);
            header.AddRange(hIdentifier);
            header.AddRange(hSize);
            header.AddRange(hVersion);
            header.Add(hFlag);
            header.AddRange(hFrameCount);
            header.AddRange(hFrameLength);
            header.AddRange(hFrameStartPos);
            return header.ToArray();
        }
        private void CreateApplicationFolder()
        {
            //string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "BookWorm");
            if (!Directory.Exists(_destinationDirectory))
                Directory.CreateDirectory(_destinationDirectory);
            else
            {
                string[] files = Directory.GetFiles(_destinationDirectory);
                foreach (string file in files)
                {
                    File.Delete(file);
                }
            }
        }
        private static byte[] ConstructExtendedHeader(string fileName)
        {
            var encoding = new UTF8Encoding();
            byte[] ehFileName = encoding.GetBytes(fileName);
            const byte ehFlag = ExtendedHeaderFlag;
            byte[] ehLastModified = BitConverter.GetBytes(File.GetLastWriteTime(fileName).Ticks);
            byte[] ehLength = BitConverter.GetBytes(ehFileName.Length + ehLastModified.Length + 1);                                       
            var extendedHeader = new List<byte>();
            extendedHeader.AddRange(ehLength);
            extendedHeader.Add(ehFlag);
            extendedHeader.AddRange(ehFileName);
            extendedHeader.AddRange(ehLastModified);            
            return extendedHeader.ToArray();            
        }       
        private static byte Reverse(byte inByte)
        {
            byte result = 0x00;
            byte mask;

            for (mask = 0x80;
                 Convert.ToInt32(mask) > 0;
                 mask >>= 1)
            {
                result >>= 1;
                var tempbyte = (byte)(inByte & mask);
                if (tempbyte != 0x00)
                    result |= 0x80;
            }
            return (result);
        }        

        [Flags]
        private enum HeaderFlags : byte
        {
            IsUnsynchronised = 1,
            HasExtendedHeader = 2
        }



    }
}